package entity

import (
	"database/sql"
	"github.com/astaxie/beego/orm"
	"github.com/gomodule/redigo/redis"
	"nspel/nspel"
	"strconv"
	"time"
)

type School struct {
	Id               int64           `orm:"pk;auto;column(id)"`
	CountryId        int64           `orm:"column(country_id)"`
	ProvinceId       int64           `orm:"column(province_id)"`
	CityId           int64           `orm:"column(city_id)"`
	AreaId           int64           `orm:"column(area_id)"`
	ExperimentAreaId int64           `orm:"column(experiment_area_id)"`
	UserId           sql.NullInt64   `orm:"column(user_id)"`
	Name             string          `orm:"column(name)"`
	SchoolCode       string          `orm:"column(school_code)"`
	Code             sql.NullString  `orm:"column(code)"`
	StudentNum       int64           `orm:"column(student_num)"`
	SchoolType       byte            `orm:"column(school_type)"`
	HeadMaster       sql.NullString  `orm:"column(headmaster)"`
	HeadMasterPhone  sql.NullString  `orm:"column(headmaster_phone)"`
	HeadMasterEmail  sql.NullString  `orm:"column(headmaster_email)"`
	Contact          sql.NullString  `orm:"column(contact)"`
	ContactPhone     sql.NullString  `orm:"column(contact_phone)"`
	ContactEmail     sql.NullString  `orm:"column(contact_email)"`
	ContactAddress   sql.NullString  `orm:"column(contact_address)"`
	HasApply         bool            `orm:"column(has_apply)"`
	Homepage         sql.NullString  `orm:"column(homepage)"`
	OfficialAccounts sql.NullString  `orm:"column(official_accounts)"`
	IsExperiment     bool            `orm:"column(is_experiment)"`
	IsStandout       bool            `orm:"column(is_standout)"`
	ExperimentAt     time.Time       `orm:"column(experiment_at)"`
	StandoutAt       time.Time       `orm:"column(standout_at)"`
	JoinAt           time.Time       `orm:"column(join_at)"`
	Score            sql.NullFloat64 `orm:"column(score)"`
	CreatedAt        time.Time       `orm:"auto_now_add;type(datetime);column(created_at)"`
	UpdatedAt        time.Time       `orm:"auto_now;type(datetime);column(updated_at)"`
}

var SchoolTypeMapCode map[byte]string
var SchoolTypeMapName map[string]interface{}

func init() {
	orm.RegisterModel(new(School))
	SchoolTypeMapCode = map[byte]string{1: "小", 2: "小初", 3: "小初高", 4: "初", 5: "初高", 6: "高"}
	SchoolTypeMapName = map[string]interface{}{"小": byte(1), "小初": byte(2), "小初高": byte(3), "初": byte(4), "初高": byte(5), "高": byte(6)}
}

func (*School) TableName() string {
	return "school"
}

func (s *School) SelectAllBySchoolCode(schoolCode string) error {
	s.SchoolCode = schoolCode
	key := "school"
	hashKey := "schoolCode[" + schoolCode + "]"
	err := nspel.RedisHgetJson(key, hashKey, s)
	if err == nil {
		return nil
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	err = nspel.GetOrmEngine().Read(s, "school_code")
	if err != nil {
		return err
	}
	nspel.RedisHsetJson(key, hashKey, s)
	return nil
}

func (s *School) SelectAllByUserId(userId int64) (err error) {
	key := "school"
	hashKey := "userId[" + strconv.FormatInt(userId, 10) + "]"
	err = nspel.RedisHgetJson(key, hashKey, s)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	s.UserId = sql.NullInt64{Int64: int64(userId), Valid: true}
	err = nspel.GetOrmEngine().Read(s, "user_id")
	if err != nil {
		return
	}
	nspel.RedisHsetJson(key, hashKey, s)
	return
}

func (s *School) SelectAllByAreaId(areaId int64) (err error, schools []School) {
	key := "school"
	hashKey := "areaId[" + strconv.FormatInt(areaId, 10) + "]"
	err = nspel.RedisHgetJson(key, hashKey, &schools)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	_, err = nspel.GetOrmEngine().QueryTable(s.TableName()).Filter("area_id", areaId).All(&schools)
	if err != nil || len(schools) == 0 {
		return
	}
	nspel.RedisHsetJson(key, hashKey, &schools)
	return
}

func (s *School) SelectAllByExperimentAreaId(experimentAreaId int64) (schools []School, err error) {
	key := "school"
	hashKey := "experimentAreaId[" + strconv.FormatInt(experimentAreaId, 10) + "]"
	err = nspel.RedisHgetJson(key, hashKey, &schools)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	_, err = nspel.GetOrmEngine().QueryTable(s.TableName()).Filter("experiment_area_id", experimentAreaId).All(&schools)
	if err != nil || len(schools) == 0 {
		return
	}
	nspel.RedisHsetJson(key, hashKey, &schools)
	return
}

func (s *School) SelectAllById(id int64) (err error) {
	key := "school"
	hashKey := "id[" + strconv.FormatInt(id, 10) + "]"
	err = nspel.RedisHgetJson(key, hashKey, s)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	s.Id = id
	err = nspel.GetOrmEngine().Read(s)
	if err != nil {
		return
	}
	nspel.RedisHsetJson(key, hashKey, s)
	return
}

func (s *School) SelectCountByProvinceIdCityIdExperimentAreaIdNameJoinAt(ormEng *orm.QuerySeter, hashKey string) (count int64, err error) {
	key := "school"
	count, err = nspel.RedisHgetInt64(key, hashKey)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	count, err = (*ormEng).Count()
	if err != nil {
		return
	}
	nspel.RedisHsetInt64(key, hashKey, count)
	return
}

func (s *School) SelectAllByProvinceIdCityIdExperimentAreaIdAreaIdNameJoinYear(ormEng *orm.QuerySeter, hashKey string) (schools []School, err error) {
	key := "school"
	err = nspel.RedisHgetJson(key, hashKey, &schools)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	_, err = (*ormEng).All(&schools)
	if err != nil || len(schools) == 0 {
		return
	}
	nspel.RedisHsetJson(key, hashKey, schools)
	return
}

func (s *School) CustomCount(ormEng *orm.QuerySeter, hashKey string) (count int64, err error) {
	key := "school"
	count, err = nspel.RedisHgetInt64(key, hashKey)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	count, err = (*ormEng).Count()
	if err != nil {
		return
	}
	nspel.RedisHsetInt64(key, hashKey, count)
	return
}

func (s *School) Insert() error {
	_, err := nspel.GetOrmEngine().Insert(s)
	return err
}

func (s *School) Update(columns ...string) error {
	_, err := nspel.GetOrmEngine().Update(s, columns...)
	return err
}

func (s *School) ImportInsert() error {
	if s.ContactPhone.Valid && len(s.ContactPhone.String) != 0 {
		manager := new(Manager)
		err := manager.SelectAllByUserName(s.ContactPhone.String)
		if err != nil {
			if err == orm.ErrNoRows {
				s.UserId, err = manager.Register(manager.UserName, manager.UserName, ManagerAuthority.School)
				if err != nil {
					return err
				}
			} else {
				return err
			}
		} else {
			s.UserId = sql.NullInt64{Int64: int64(manager.Id), Valid: true}
		}
	}
	err := s.Insert()
	return err
}

func (s *School) ImportUpdate() error {
	if s.ContactPhone.Valid && len(s.ContactPhone.String) != 0 && !s.UserId.Valid {
		manager := new(Manager)
		err := manager.SelectAllByUserName(s.ContactPhone.String)
		if err != nil {
			if err == orm.ErrNoRows {
				s.UserId, err = manager.Register(manager.UserName, manager.UserName, ManagerAuthority.School)
				if err != nil {
					return err
				}
			} else {
				return err
			}
		} else {
			s.UserId = sql.NullInt64{Int64: int64(manager.Id), Valid: true}
		}
	}
	err := s.Update("experiment_area_id", "user_id", "name", "school_code", "code", "student_num", "school_type", "headmaster", "headmaster_phone", "headmaster_email", "contact", "contact_phone", "contact_email", "contact_address", "has_apply", "homepage", "official_accounts", "is_experiment", "is_standout", "experiment_at", "standout_at", "join_at")
	return err
}

func (s *School) SelectCountByExperimentAreaId(experimentAreaId int64) (int64, error) {
	key := "school"
	hashKey := "experimentAreaId[" + strconv.FormatInt(experimentAreaId, 10) + "].count"
	count, err := nspel.RedisHgetInt64(key, hashKey)
	if err == nil {
		return int64(count), nil
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	count, err = nspel.GetOrmEngine().QueryTable(s.TableName()).Filter("experiment_area_id", experimentAreaId).Count()
	if err != nil {
		return 0, err
	}
	nspel.RedisHsetInt64(key, hashKey, count)
	return int64(count), nil
}

func (s *School) SelectCountByExperimentAreaIdIsStandout(experimentAreaId int64, isStandout bool) (int64, error) {
	key := "school"
	hashKey := "experimentAreaId[" + strconv.FormatInt(experimentAreaId, 10) + "].isStandout[" + strconv.FormatBool(isStandout) + "].count"
	count, err := nspel.RedisHgetInt64(key, hashKey)
	if err == nil {
		return int64(count), nil
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	count, err = nspel.GetOrmEngine().QueryTable(s.TableName()).Filter("experiment_area_id", experimentAreaId).Filter("is_standout", isStandout).Count()
	if err != nil {
		return 0, err
	}
	nspel.RedisHsetInt64(key, hashKey, count)
	return int64(count), nil
}

func (s *School) DeleteById(id int64) error {
	s.Id = id
	_, err := nspel.GetOrmEngine().Delete(s)
	return err
}

func (s *School) SelectCountByProvinceId(provinceId int64) (count int64, err error) {
	key := "school"
	hashKey := "provinceId[" + strconv.FormatInt(provinceId, 10) + "].count"
	count, err = nspel.RedisHgetInt64(key, hashKey)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	count, err = nspel.GetOrmEngine().QueryTable(s.TableName()).Filter("province_id", provinceId).Count()
	nspel.RedisHsetInt64(key, hashKey, count)
	return count, err
}

func (s *School) SelectCountByProvinceIdIsStandout(provinceId int64, isStandout bool) (count int64, err error) {
	key := "school"
	hashKey := "provinceId[" + strconv.FormatInt(provinceId, 10) + "].isStandout[" + strconv.FormatBool(isStandout) + "].count"
	count, err = nspel.RedisHgetInt64(key, hashKey)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	count, err = nspel.GetOrmEngine().QueryTable(s.TableName()).Filter("province_id", provinceId).Filter("is_standout", isStandout).Count()
	nspel.RedisHsetInt64(key, hashKey, count)
	return count, err
}

func (s *School) SelectAllByExperimentAreaIdOrderByScoreDesc(experimentAreaId int64, limit int64) (schools []School, err error) {
	key := "school"
	hashKey := "experimentAreaId[" + strconv.FormatInt(experimentAreaId, 10) + "].limit[" + strconv.FormatInt(limit, 10) + "].orderBy[scoreDesc]"
	err = nspel.RedisHgetJson(key, hashKey, &schools)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	_, err = nspel.GetOrmEngine().QueryTable(s.TableName()).Filter("experiment_area_id", experimentAreaId).Limit(limit).OrderBy("-score").All(&schools)
	if err != nil || len(schools) == 0 {
		return
	}
	nspel.RedisHsetJson(key, hashKey, schools)
	return
}
